home *** CD-ROM | disk | FTP | other *** search
/ PC PowerPlay 22 / PCPP #22.iso / Quake2 / q2source_12_11 / game / p_weapon.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-11-26  |  29.3 KB  |  1,246 lines

  1. // g_weapon.c
  2.  
  3. #include "g_local.h"
  4. #include "m_player.h"
  5.  
  6.  
  7. static qboolean    is_quad;
  8. static byte        is_silenced;
  9.  
  10. static void P_ProjectSource (gclient_t *client, vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result)
  11. {
  12.     vec3_t    _distance;
  13.  
  14.     VectorCopy (distance, _distance);
  15.     if (client->pers.hand == LEFT_HANDED)
  16.         _distance[1] *= -1;
  17.     else if (client->pers.hand == CENTER_HANDED)
  18.         _distance[1] = 0;
  19.     G_ProjectSource (point, _distance, forward, right, result);
  20. }
  21.  
  22.  
  23. /*
  24. ===============
  25. PlayerNoise
  26.  
  27. Each player can have two noise objects associated with it:
  28. a personal noise (jumping, pain, weapon firing), and a weapon
  29. target noise (bullet wall impacts)
  30.  
  31. Monsters that don't directly see the player can move
  32. to a noise in hopes of seeing the player from there.
  33. ===============
  34. */
  35. void PlayerNoise(edict_t *who, vec3_t where, int type)
  36. {
  37.     edict_t        *noise;
  38.  
  39.     if (type == PNOISE_WEAPON)
  40.     {
  41.         if (who->client->silencer_shots)
  42.         {
  43.             who->client->silencer_shots--;
  44.             return;
  45.         }
  46.     }
  47.  
  48.     if (deathmatch->value)
  49.         return;
  50.  
  51.     if (who->flags & FL_NOTARGET)
  52.         return;
  53.  
  54.  
  55.     if (!who->mynoise)
  56.     {
  57.         noise = G_Spawn();
  58.         noise->classname = "player_noise";
  59.         VectorSet (noise->mins, -8, -8, -8);
  60.         VectorSet (noise->maxs, 8, 8, 8);
  61.         noise->owner = who;
  62.         noise->svflags = SVF_NOCLIENT;
  63.         who->mynoise = noise;
  64.  
  65.         noise = G_Spawn();
  66.         noise->classname = "player_noise";
  67.         VectorSet (noise->mins, -8, -8, -8);
  68.         VectorSet (noise->maxs, 8, 8, 8);
  69.         noise->owner = who;
  70.         noise->svflags = SVF_NOCLIENT;
  71.         who->mynoise2 = noise;
  72.     }
  73.  
  74.     if (type == PNOISE_SELF || type == PNOISE_WEAPON)
  75.     {
  76.         noise = who->mynoise;
  77.         level.sound_entity = noise;
  78.         level.sound_entity_framenum = level.framenum;
  79.     }
  80.     else // type == PNOISE_IMPACT
  81.     {
  82.         noise = who->mynoise2;
  83.         level.sound2_entity = noise;
  84.         level.sound2_entity_framenum = level.framenum;
  85.     }
  86.  
  87.     VectorCopy (where, noise->s.origin);
  88.     VectorSubtract (where, noise->maxs, noise->absmin);
  89.     VectorAdd (where, noise->maxs, noise->absmax);
  90.     noise->teleport_time = level.time;
  91.     gi.linkentity (noise);
  92. }
  93.  
  94.  
  95. qboolean Pickup_Weapon (edict_t *ent, edict_t *other)
  96. {
  97.     int            index;
  98.     gitem_t        *ammo;
  99.  
  100.     index = ITEM_INDEX(ent->item);
  101.  
  102.     if ( ((int)(dmflags->value) & DF_WEAPONS_STAY) && other->client->pers.inventory[index])
  103.     {
  104.         if (!(ent->spawnflags & (DROPPED_ITEM | DROPPED_PLAYER_ITEM) ) )
  105.             return false;    // leave the weapon for others to pickup
  106.     }
  107.  
  108.     other->client->pers.inventory[index]++;
  109.  
  110.     if (!(ent->spawnflags & DROPPED_ITEM) )
  111.     {
  112.         // give them some ammo with it
  113.         ammo = FindItem (ent->item->ammo);
  114.         Add_Ammo (other, ammo, ammo->quantity);
  115.  
  116.         if (! (ent->spawnflags & DROPPED_PLAYER_ITEM) )
  117.         {
  118.             if (deathmatch->value)
  119.             {
  120.                 if ((int)(dmflags->value) & DF_WEAPONS_STAY)
  121.                     ent->flags |= FL_RESPAWN;
  122.                 else
  123.                     SetRespawn (ent, 30);
  124.             }
  125.         }
  126.     }
  127.  
  128.     if (other->client->pers.weapon != ent->item && 
  129.         ( !deathmatch->value || other->client->pers.weapon == FindItem("blaster") ) )
  130.         other->client->newweapon = ent->item;
  131.  
  132.     return true;
  133. }
  134.  
  135.  
  136. /*
  137. ===============
  138. ChangeWeapon
  139.  
  140. The old weapon has been dropped all the way, so make the new one
  141. current
  142. ===============
  143. */
  144. void ChangeWeapon (edict_t *ent)
  145. {
  146.     ent->client->pers.weapon = ent->client->newweapon;
  147.     ent->client->newweapon = NULL;
  148.     ent->client->machinegun_shots = 0;
  149.  
  150.     if (ent->client->pers.weapon && ent->client->pers.weapon->ammo)
  151.         ent->client->ammo_index = ITEM_INDEX(FindItem(ent->client->pers.weapon->ammo));
  152.     else
  153.         ent->client->ammo_index = 0;
  154.  
  155.     if (!ent->client->pers.weapon)
  156.     {    // dead
  157.         ent->client->ps.gunindex = 0;
  158.         return;
  159.     }
  160.  
  161.     ent->client->weaponstate = WEAPON_ACTIVATING;
  162.     ent->client->ps.gunframe = 0;
  163.     ent->client->ps.gunindex = gi.modelindex(ent->client->pers.weapon->view_model);
  164. }
  165.  
  166. /*
  167. =================
  168. NoAmmoWeaponChange
  169. =================
  170. */
  171. void NoAmmoWeaponChange (edict_t *ent)
  172. {
  173.     if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("slugs"))]
  174.         &&  ent->client->pers.inventory[ITEM_INDEX(FindItem("railgun"))] )
  175.     {
  176.         ent->client->newweapon = FindItem ("railgun");
  177.         return;
  178.     }
  179.     if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("cells"))]
  180.         &&  ent->client->pers.inventory[ITEM_INDEX(FindItem("hyperblaster"))] )
  181.     {
  182.         ent->client->newweapon = FindItem ("hyperblaster");
  183.         return;
  184.     }
  185.     if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("bullets"))]
  186.         &&  ent->client->pers.inventory[ITEM_INDEX(FindItem("chaingun"))] )
  187.     {
  188.         ent->client->newweapon = FindItem ("chaingun");
  189.         return;
  190.     }
  191.     if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("bullets"))]
  192.         &&  ent->client->pers.inventory[ITEM_INDEX(FindItem("machinegun"))] )
  193.     {
  194.         ent->client->newweapon = FindItem ("machinegun");
  195.         return;
  196.     }
  197.     if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("shells"))]
  198.         &&  ent->client->pers.inventory[ITEM_INDEX(FindItem("super shotgun"))] )
  199.     {
  200.         ent->client->newweapon = FindItem ("super shotgun");
  201.         return;
  202.     }
  203.     if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("shells"))]
  204.         &&  ent->client->pers.inventory[ITEM_INDEX(FindItem("shotgun"))] )
  205.     {
  206.         ent->client->newweapon = FindItem ("shotgun");
  207.         return;
  208.     }
  209.     ent->client->newweapon = FindItem ("blaster");
  210. }
  211.  
  212. /*
  213. =================
  214. Think_Weapon
  215.  
  216. Called by ClientBeginServerFrame and ClientThink
  217. =================
  218. */
  219. void Think_Weapon (edict_t *ent)
  220. {
  221.     // if just died, put the weapon away
  222.     if (ent->health < 1)
  223.     {
  224.         ent->client->newweapon = NULL;
  225.         ChangeWeapon (ent);
  226.     }
  227.  
  228.     if (g_unlimited_ammo->value)
  229.     {
  230.         if (ent->client->ammo_index)
  231.             ent->client->pers.inventory[ent->client->ammo_index] = 999;
  232.         //FIXME make this be the actual max
  233.     }
  234.  
  235.     // call active weapon think routine
  236.     if (ent->client->pers.weapon && ent->client->pers.weapon->weaponthink)
  237.     {
  238.         is_quad = (ent->client->quad_framenum > level.framenum);
  239.         if (ent->client->silencer_shots)
  240.             is_silenced = MZ_SILENCED;
  241.         else
  242.             is_silenced = 0;
  243.         ent->client->pers.weapon->weaponthink (ent);
  244.     }
  245. }
  246.  
  247.  
  248. /*
  249. ================
  250. Use_Weapon
  251.  
  252. Make the weapon ready if there is ammo
  253. ================
  254. */
  255. void Use_Weapon (edict_t *ent, gitem_t *item)
  256. {
  257.     int            ammo_index;
  258.     gitem_t        *ammo_item;
  259.  
  260.     // see if we're already using it
  261.     if (item == ent->client->pers.weapon)
  262.         return;
  263.  
  264.     if (item->ammo)
  265.     {
  266.         ammo_item = FindItem(item->ammo);
  267.         ammo_index = ITEM_INDEX(ammo_item);
  268.         if (!ent->client->pers.inventory[ammo_index] && !g_select_empty->value)
  269.         {
  270.             gi.cprintf (ent, PRINT_HIGH, "No %s for %s.\n", ammo_item->pickup_name, item->pickup_name);
  271.             return;
  272.         }
  273.     }
  274.  
  275.     // change to this weapon when down
  276.     ent->client->newweapon = item;
  277. }
  278.  
  279.  
  280.  
  281. /*
  282. ================
  283. Drop_Weapon
  284. ================
  285. */
  286. void Drop_Weapon (edict_t *ent, gitem_t *item)
  287. {
  288.     int        index;
  289.  
  290.     index = ITEM_INDEX(item);
  291.     // see if we're already using it
  292.     if ( (item == ent->client->pers.weapon) && (ent->client->pers.inventory[index] == 1) )
  293.     {
  294.         gi.cprintf (ent, PRINT_HIGH, "Can't drop - Weapon is in use\n");
  295.         return;
  296.     }
  297.  
  298.     Drop_Item (ent, item);
  299.     ent->client->pers.inventory[index]--;
  300. }
  301.  
  302.  
  303. /*
  304. ================
  305. Weapon_Generic
  306.  
  307. A generic function to handle the basics of weapon thinking
  308. ================
  309. */
  310. #define FRAME_FIRE_FIRST        (FRAME_ACTIVATE_LAST + 1)
  311. #define FRAME_IDLE_FIRST        (FRAME_FIRE_LAST + 1)
  312. #define FRAME_DEACTIVATE_FIRST    (FRAME_IDLE_LAST + 1)
  313.  
  314. void Weapon_Generic (edict_t *ent, int FRAME_ACTIVATE_LAST, int FRAME_FIRE_LAST, int FRAME_IDLE_LAST, int FRAME_DEACTIVATE_LAST, int *pause_frames, int *fire_frames, void (*fire)(edict_t *ent))
  315. {
  316.     int        n;
  317.  
  318.     if (ent->client->weaponstate == WEAPON_DROPPING)
  319.     {
  320.         if (ent->client->ps.gunframe == FRAME_DEACTIVATE_LAST)
  321.         {
  322.             ChangeWeapon (ent);
  323.             return;
  324.         }
  325.  
  326.         ent->client->ps.gunframe++;
  327.         return;
  328.     }
  329.  
  330.     if (ent->client->weaponstate == WEAPON_ACTIVATING)
  331.     {
  332.         if (ent->client->ps.gunframe == FRAME_ACTIVATE_LAST)
  333.         {
  334.             ent->client->weaponstate = WEAPON_READY;
  335.             ent->client->ps.gunframe = FRAME_IDLE_FIRST;
  336.             return;
  337.         }
  338.  
  339.         ent->client->ps.gunframe++;
  340.         return;
  341.     }
  342.  
  343.     if ((ent->client->newweapon) && (ent->client->weaponstate != WEAPON_FIRING))
  344.     {
  345.         ent->client->weaponstate = WEAPON_DROPPING;
  346.         ent->client->ps.gunframe = FRAME_DEACTIVATE_FIRST;
  347.         return;
  348.     }
  349.  
  350.     if (ent->client->weaponstate == WEAPON_READY)
  351.     {
  352.         if ( ((ent->client->latched_buttons|ent->client->buttons) & BUTTON_ATTACK) )
  353.         {
  354.             ent->client->latched_buttons &= ~BUTTON_ATTACK;
  355.             if ((!ent->client->ammo_index) || 
  356.                 ( ent->client->pers.inventory[ent->client->ammo_index] >= ent->client->pers.weapon->quantity))
  357.             {
  358.                 ent->client->ps.gunframe = FRAME_FIRE_FIRST;
  359.                 ent->client->weaponstate = WEAPON_FIRING;
  360.  
  361.                 // start the animation
  362.                 ent->client->anim_priority = ANIM_ATTACK;
  363.                 if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
  364.                 {
  365.                     ent->s.frame = FRAME_crattak1-1;
  366.                     ent->client->anim_end = FRAME_crattak9;
  367.                 }
  368.                 else
  369.                 {
  370.                     ent->s.frame = FRAME_attack1-1;
  371.                     ent->client->anim_end = FRAME_attack8;
  372.                 }
  373.             }
  374.             else
  375.             {
  376.                 if (level.time >= ent->pain_debounce_time)
  377.                 {
  378.                     gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
  379.                     ent->pain_debounce_time = level.time + 1;
  380.                 }
  381.                 NoAmmoWeaponChange (ent);
  382.             }
  383.         }
  384.         else
  385.         {
  386.             if (ent->client->ps.gunframe == FRAME_IDLE_LAST)
  387.             {
  388.                 ent->client->ps.gunframe = FRAME_IDLE_FIRST;
  389.                 return;
  390.             }
  391.  
  392.             if (pause_frames)
  393.             {
  394.                 for (n = 0; pause_frames[n]; n++)
  395.                 {
  396.                     if (ent->client->ps.gunframe == pause_frames[n])
  397.                     {
  398.                         if (rand()&15)
  399.                             return;
  400.                     }
  401.                 }
  402.             }
  403.  
  404.             ent->client->ps.gunframe++;
  405.             return;
  406.         }
  407.     }
  408.  
  409.     if (ent->client->weaponstate == WEAPON_FIRING)
  410.     {
  411.         for (n = 0; fire_frames[n]; n++)
  412.         {
  413.             if (ent->client->ps.gunframe == fire_frames[n])
  414.             {
  415.                 if (ent->client->quad_framenum > level.framenum)
  416.                     gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage3.wav"), 1, ATTN_NORM, 0);
  417.  
  418.                 fire (ent);
  419.                 break;
  420.             }
  421.         }
  422.  
  423.         if (!fire_frames[n])
  424.             ent->client->ps.gunframe++;
  425.  
  426.         if (ent->client->ps.gunframe == FRAME_IDLE_FIRST+1)
  427.             ent->client->weaponstate = WEAPON_READY;
  428.     }
  429. }
  430.  
  431.  
  432. /*
  433. ======================================================================
  434.  
  435. GRENADE
  436.  
  437. ======================================================================
  438. */
  439.  
  440. #define GRENADE_TIMER        3.0
  441. #define GRENADE_MINSPEED    400
  442. #define GRENADE_MAXSPEED    800
  443.  
  444. void weapon_grenade_fire (edict_t *ent)
  445. {
  446.     vec3_t    offset;
  447.     vec3_t    forward, right;
  448.     vec3_t    start;
  449.     int        damage = 125;
  450.     float    timer;
  451.     int        speed;
  452.     float    radius;
  453.  
  454.     radius = damage+40;
  455.     if (is_quad)
  456.         damage *= 4;
  457.  
  458.     VectorSet(offset, 8, 8, ent->viewheight-8);
  459.     AngleVectors (ent->client->v_angle, forward, right, NULL);
  460.     P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  461.  
  462.     timer = ent->client->grenade_time - level.time;
  463.     speed = GRENADE_MINSPEED + (GRENADE_TIMER - timer) * ((GRENADE_MAXSPEED - GRENADE_MINSPEED) / GRENADE_TIMER);
  464.     fire_grenade2 (ent, start, forward, damage, speed, timer, radius);
  465.  
  466.     ent->client->pers.inventory[ent->client->ammo_index]--;
  467.  
  468.     ent->client->grenade_time = level.time + 1.0;
  469. }
  470.  
  471. void Weapon_Grenade (edict_t *ent)
  472. {
  473.     if ((ent->client->newweapon) && (ent->client->weaponstate == WEAPON_READY))
  474.     {
  475.         ChangeWeapon (ent);
  476.         return;
  477.     }
  478.  
  479.     if (ent->client->weaponstate == WEAPON_ACTIVATING)
  480.     {
  481.         ent->client->weaponstate = WEAPON_READY;
  482.         ent->client->ps.gunframe = 16;
  483.         return;
  484.     }
  485.  
  486.     if (ent->client->weaponstate == WEAPON_READY)
  487.     {
  488.         if ( ((ent->client->latched_buttons|ent->client->buttons) & BUTTON_ATTACK) )
  489.         {
  490.             ent->client->latched_buttons &= ~BUTTON_ATTACK;
  491.             if (ent->client->pers.inventory[ent->client->ammo_index])
  492.             {
  493.                 ent->client->ps.gunframe = 1;
  494.                 ent->client->weaponstate = WEAPON_FIRING;
  495.                 ent->client->grenade_time = 0;
  496.             }
  497.             else
  498.             {
  499.                 if (level.time >= ent->pain_debounce_time)
  500.                 {
  501.                     gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
  502.                     ent->pain_debounce_time = level.time + 1;
  503.                 }
  504.                 NoAmmoWeaponChange (ent);
  505.             }
  506.             return;
  507.         }
  508.  
  509.         if ((ent->client->ps.gunframe == 29) || (ent->client->ps.gunframe == 34) || (ent->client->ps.gunframe == 39) || (ent->client->ps.gunframe == 48))
  510.         {
  511.             if (rand()&15)
  512.                 return;
  513.         }
  514.  
  515.         if (++ent->client->ps.gunframe > 48)
  516.             ent->client->ps.gunframe = 16;
  517.         return;
  518.     }
  519.  
  520.     if (ent->client->weaponstate == WEAPON_FIRING)
  521.     {
  522.         if (ent->client->ps.gunframe == 5)
  523.             gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/hgrena1b.wav"), 1, ATTN_NORM, 0);
  524.  
  525.         if (ent->client->ps.gunframe == 11)
  526.         {
  527.             if (!ent->client->grenade_time)
  528.             {
  529.                 ent->client->grenade_time = level.time + GRENADE_TIMER + 0.2;
  530.                 ent->client->weapon_sound = gi.soundindex("weapons/hgrenc1b.wav");
  531.             }
  532.  
  533.             // they waited too long, detonate it in their hand
  534.             if (!ent->client->grenade_blew_up && level.time >= ent->client->grenade_time)
  535.             {
  536.                 ent->client->weapon_sound = 0;
  537.                 weapon_grenade_fire (ent);
  538.                 ent->client->grenade_blew_up = true;
  539.             }
  540.  
  541.             if (ent->client->buttons & BUTTON_ATTACK)
  542.                 return;
  543.  
  544.             if (ent->client->grenade_blew_up)
  545.             {
  546.                 if (level.time >= ent->client->grenade_time)
  547.                 {
  548.                     ent->client->ps.gunframe = 15;
  549.                     ent->client->grenade_blew_up = false;
  550.                 }
  551.                 else
  552.                 {
  553.                     return;
  554.                 }
  555.             }
  556.         }
  557.  
  558.         if (ent->client->ps.gunframe == 12)
  559.         {
  560.             ent->client->weapon_sound = 0;
  561.             weapon_grenade_fire (ent);
  562.         }
  563.  
  564.         if ((ent->client->ps.gunframe == 15) && (level.time < ent->client->grenade_time))
  565.             return;
  566.  
  567.         ent->client->ps.gunframe++;
  568.  
  569.         if (ent->client->ps.gunframe == 16)
  570.             ent->client->weaponstate = WEAPON_READY;
  571.     }
  572. }
  573.  
  574. /*
  575. ======================================================================
  576.  
  577. GRENADE LAUNCHER
  578.  
  579. ======================================================================
  580. */
  581.  
  582. void weapon_grenadelauncher_fire (edict_t *ent)
  583. {
  584.     vec3_t    offset;
  585.     vec3_t    forward, right;
  586.     vec3_t    start;
  587.     int        damage = 120;
  588.     float    radius;
  589.  
  590.     radius = damage+40;
  591.     if (is_quad)
  592.         damage *= 4;
  593.  
  594.     VectorSet(offset, 8, 8, ent->viewheight-8);
  595.     AngleVectors (ent->client->v_angle, forward, right, NULL);
  596.     P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  597.  
  598.     VectorScale (forward, -2, ent->client->kick_origin);
  599.     ent->client->kick_angles[0] = -1;
  600.  
  601.     fire_grenade (ent, start, forward, damage, 600, 2.5, radius);
  602.  
  603.     gi.WriteByte (svc_muzzleflash);
  604.     gi.WriteShort (ent-g_edicts);
  605.     gi.WriteByte (MZ_GRENADE | is_silenced);
  606.     gi.multicast (ent->s.origin, MULTICAST_PVS);
  607.  
  608.     ent->client->ps.gunframe++;
  609.  
  610.     PlayerNoise(ent, start, PNOISE_WEAPON);
  611.  
  612.     ent->client->pers.inventory[ent->client->ammo_index] -= ent->client->pers.weapon->quantity;
  613. }
  614.  
  615. void Weapon_GrenadeLauncher (edict_t *ent)
  616. {
  617.     static int    pause_frames[]    = {34, 51, 59, 0};
  618.     static int    fire_frames[]    = {6, 0};
  619.  
  620.     Weapon_Generic (ent, 5, 16, 59, 64, pause_frames, fire_frames, weapon_grenadelauncher_fire);
  621. }
  622.  
  623. /*
  624. ======================================================================
  625.  
  626. ROCKET
  627.  
  628. ======================================================================
  629. */
  630.  
  631. void Weapon_RocketLauncher_Fire (edict_t *ent)
  632. {
  633.     vec3_t    offset, start;
  634.     vec3_t    forward, right;
  635.     int        damage;
  636.     float    damage_radius;
  637.     int        radius_damage;
  638.  
  639.     damage = 100 + (int)(random() * 20.0);
  640.     radius_damage = 120;
  641.     damage_radius = 120;
  642.     if (is_quad)
  643.     {
  644.         damage *= 4;
  645.         radius_damage *= 4;
  646.     }
  647.  
  648.     AngleVectors (ent->client->v_angle, forward, right, NULL);
  649.  
  650.     VectorScale (forward, -2, ent->client->kick_origin);
  651.     ent->client->kick_angles[0] = -1;
  652.  
  653.     VectorSet(offset, 8, 8, ent->viewheight-8);
  654.     P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  655.     fire_rocket (ent, start, forward, damage, 550, damage_radius, radius_damage);
  656.  
  657.     // send muzzle flash
  658.     gi.WriteByte (svc_muzzleflash);
  659.     gi.WriteShort (ent-g_edicts);
  660.     gi.WriteByte (MZ_ROCKET | is_silenced);
  661.     gi.multicast (ent->s.origin, MULTICAST_PVS);
  662.  
  663.     ent->client->ps.gunframe++;
  664.  
  665.     PlayerNoise(ent, start, PNOISE_WEAPON);
  666.  
  667.     ent->client->pers.inventory[ent->client->ammo_index] -= ent->client->pers.weapon->quantity;
  668. }
  669.  
  670. void Weapon_RocketLauncher (edict_t *ent)
  671. {
  672.     static int    pause_frames[]    = {25, 33, 42, 50, 0};
  673.     static int    fire_frames[]    = {5, 0};
  674.  
  675.     Weapon_Generic (ent, 4, 12, 50, 54, pause_frames, fire_frames, Weapon_RocketLauncher_Fire);
  676. }
  677.  
  678.  
  679. /*
  680. ======================================================================
  681.  
  682. BLASTER / HYPERBLASTER
  683.  
  684. ======================================================================
  685. */
  686.  
  687. void Blaster_Fire (edict_t *ent, vec3_t g_offset, int damage, qboolean hyper, int effect)
  688. {
  689.     vec3_t    forward, right;
  690.     vec3_t    start;
  691.     vec3_t    offset;
  692.  
  693.     if (is_quad)
  694.         damage *= 4;
  695.     AngleVectors (ent->client->v_angle, forward, right, NULL);
  696.     VectorSet(offset, 24, 8, ent->viewheight-8);
  697.     VectorAdd (offset, g_offset, offset);
  698.     P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  699.  
  700.     VectorScale (forward, -2, ent->client->kick_origin);
  701.     ent->client->kick_angles[0] = -1;
  702.  
  703.     fire_blaster (ent, start, forward, damage, 1000, effect);
  704.  
  705.     // send muzzle flash
  706.     gi.WriteByte (svc_muzzleflash);
  707.     gi.WriteShort (ent-g_edicts);
  708.     if (hyper)
  709.         gi.WriteByte (MZ_HYPERBLASTER | is_silenced);
  710.     else
  711.         gi.WriteByte (MZ_BLASTER | is_silenced);
  712.     gi.multicast (ent->s.origin, MULTICAST_PVS);
  713.  
  714.     PlayerNoise(ent, start, PNOISE_WEAPON);
  715. }
  716.  
  717.  
  718. void Weapon_Blaster_Fire (edict_t *ent)
  719. {
  720.     int        damage;
  721.  
  722.     if (deathmatch->value)
  723.         damage = 15;
  724.     else
  725.         damage = 10;
  726.     Blaster_Fire (ent, vec3_origin, damage, false, EF_BLASTER);
  727.     ent->client->ps.gunframe++;
  728. }
  729.  
  730. void Weapon_Blaster (edict_t *ent)
  731. {
  732.     static int    pause_frames[]    = {19, 32, 0};
  733.     static int    fire_frames[]    = {5, 0};
  734.  
  735.     Weapon_Generic (ent, 4, 8, 52, 55, pause_frames, fire_frames, Weapon_Blaster_Fire);
  736. }
  737.  
  738.  
  739. void Weapon_HyperBlaster_Fire (edict_t *ent)
  740. {
  741.     float    rotation;
  742.     vec3_t    offset;
  743.     int        effect;
  744.  
  745.     ent->client->weapon_sound = gi.soundindex("weapons/hyprbl1a.wav");
  746.  
  747.     if (!(ent->client->buttons & BUTTON_ATTACK))
  748.     {
  749.         ent->client->ps.gunframe++;
  750.     }
  751.     else
  752.     {
  753.         if (! ent->client->pers.inventory[ent->client->ammo_index] )
  754.         {
  755.             if (level.time >= ent->pain_debounce_time)
  756.             {
  757.                 gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
  758.                 ent->pain_debounce_time = level.time + 1;
  759.             }
  760.             NoAmmoWeaponChange (ent);
  761.         }
  762.         else
  763.         {
  764.             rotation = (ent->client->ps.gunframe - 5) * 2*M_PI/6;
  765.             offset[0] = -4 * sin(rotation);
  766.             offset[1] = 0;
  767.             offset[2] = 4 * cos(rotation);
  768.  
  769.             if ((ent->client->ps.gunframe == 6) || (ent->client->ps.gunframe == 9))
  770.                 effect = EF_HYPERBLASTER;
  771.             else
  772.                 effect = 0;
  773.             Blaster_Fire (ent, offset, 20, true, effect);
  774.             ent->client->pers.inventory[ent->client->ammo_index] -= ent->client->pers.weapon->quantity;
  775.         }
  776.  
  777.         ent->client->ps.gunframe++;
  778.         if (ent->client->ps.gunframe == 12 && ent->client->pers.inventory[ent->client->ammo_index])
  779.             ent->client->ps.gunframe = 6;
  780.     }
  781.  
  782.     if (ent->client->ps.gunframe == 12)
  783.     {
  784.         gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/hyprbd1a.wav"), 1, ATTN_NORM, 0);
  785.         ent->client->weapon_sound = 0;
  786.     }
  787.  
  788. }
  789.  
  790. void Weapon_HyperBlaster (edict_t *ent)
  791. {
  792.     static int    pause_frames[]    = {0};
  793.     static int    fire_frames[]    = {6, 7, 8, 9, 10, 11, 0};
  794.  
  795.     Weapon_Generic (ent, 5, 20, 49, 53, pause_frames, fire_frames, Weapon_HyperBlaster_Fire);
  796. }
  797.  
  798. /*
  799. ======================================================================
  800.  
  801. MACHINEGUN / CHAINGUN
  802.  
  803. ======================================================================
  804. */
  805.  
  806. void Machinegun_Fire (edict_t *ent)
  807. {
  808.     int    i;
  809.     vec3_t        start;
  810.     vec3_t        forward, right;
  811.     vec3_t        angles;
  812.     int            damage = 8;
  813.     int            kick = 2;
  814.     vec3_t        offset;
  815.  
  816.     if (!(ent->client->buttons & BUTTON_ATTACK))
  817.     {
  818.         ent->client->machinegun_shots = 0;
  819.         ent->client->ps.gunframe++;
  820.         return;
  821.     }
  822.  
  823.     if (ent->client->ps.gunframe == 5)
  824.         ent->client->ps.gunframe = 4;
  825.     else
  826.         ent->client->ps.gunframe = 5;
  827.  
  828.     if (ent->client->pers.inventory[ent->client->ammo_index] < 1)
  829.     {
  830.         ent->client->ps.gunframe = 6;
  831.         if (level.time >= ent->pain_debounce_time)
  832.         {
  833.             gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
  834.             ent->pain_debounce_time = level.time + 1;
  835.         }
  836.         NoAmmoWeaponChange (ent);
  837.         return;
  838.     }
  839.  
  840.     if (is_quad)
  841.     {
  842.         damage *= 4;
  843.         kick *= 4;
  844.     }
  845.  
  846.     for (i=1 ; i<3 ; i++)
  847.     {
  848.         ent->client->kick_origin[i] = crandom() * 0.35;
  849.         ent->client->kick_angles[i] = crandom() * 0.7;
  850.     }
  851.     ent->client->kick_origin[0] = crandom() * 0.35;
  852.     ent->client->kick_angles[0] = ent->client->machinegun_shots * -1.5;
  853.  
  854.     // raise the gun as it is firing
  855.     if (!deathmatch->value)
  856.     {
  857.         ent->client->machinegun_shots++;
  858.         if (ent->client->machinegun_shots > 9)
  859.             ent->client->machinegun_shots = 9;
  860.     }
  861.  
  862.     // get start / end positions
  863.     VectorAdd (ent->client->v_angle, ent->client->kick_angles, angles);
  864.     AngleVectors (angles, forward, right, NULL);
  865.     VectorSet(offset, 0, 8, ent->viewheight-8);
  866.     P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  867.     fire_bullet (ent, start, forward, damage, kick, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD);
  868.  
  869.     gi.WriteByte (svc_muzzleflash);
  870.     gi.WriteShort (ent-g_edicts);
  871.     gi.WriteByte (MZ_MACHINEGUN | is_silenced);
  872.     gi.multicast (ent->s.origin, MULTICAST_PVS);
  873.  
  874.     PlayerNoise(ent, start, PNOISE_WEAPON);
  875.  
  876.     ent->client->pers.inventory[ent->client->ammo_index] -= ent->client->pers.weapon->quantity;
  877. }
  878.  
  879. void Weapon_Machinegun (edict_t *ent)
  880. {
  881.     static int    pause_frames[]    = {23, 45, 0};
  882.     static int    fire_frames[]    = {4, 5, 0};
  883.  
  884.     Weapon_Generic (ent, 3, 5, 45, 49, pause_frames, fire_frames, Machinegun_Fire);
  885. }
  886.  
  887. void Chaingun_Fire (edict_t *ent)
  888. {
  889.     int            i;
  890.     int            shots;
  891.     vec3_t        start;
  892.     vec3_t        forward, right, up;
  893.     float        r, u;
  894.     vec3_t        offset;
  895.     int            damage;
  896.     int            kick = 2;
  897.  
  898.     if (deathmatch->value)
  899.         damage = 6;
  900.     else
  901.         damage = 8;
  902.  
  903.     if (ent->client->ps.gunframe == 5)
  904.         gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/chngnu1a.wav"), 1, ATTN_IDLE, 0);
  905.  
  906.     if ((ent->client->ps.gunframe == 14) && !(ent->client->buttons & BUTTON_ATTACK))
  907.     {
  908.         ent->client->ps.gunframe = 32;
  909.         ent->client->weapon_sound = 0;
  910.         return;
  911.     }
  912.     else if ((ent->client->ps.gunframe == 21) && (ent->client->buttons & BUTTON_ATTACK)
  913.         && ent->client->pers.inventory[ent->client->ammo_index])
  914.     {
  915.         ent->client->ps.gunframe = 15;
  916.     }
  917.     else
  918.     {
  919.         ent->client->ps.gunframe++;
  920.     }
  921.  
  922.     if (ent->client->ps.gunframe == 22)
  923.     {
  924.         ent->client->weapon_sound = 0;
  925.         gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/chngnd1a.wav"), 1, ATTN_IDLE, 0);
  926.     }
  927.     else
  928.     {
  929.         ent->client->weapon_sound = gi.soundindex("weapons/chngnl1a.wav");
  930.     }
  931.  
  932.     if (ent->client->ps.gunframe <= 9)
  933.         shots = 1;
  934.     else if (ent->client->ps.gunframe <= 14)
  935.     {
  936.         if (ent->client->buttons & BUTTON_ATTACK)
  937.             shots = 2;
  938.         else
  939.             shots = 1;
  940.     }
  941.     else
  942.         shots = 3;
  943.  
  944.     if (ent->client->pers.inventory[ent->client->ammo_index] < shots)
  945.         shots = ent->client->pers.inventory[ent->client->ammo_index];
  946.  
  947.     if (!shots)
  948.     {
  949.         if (level.time >= ent->pain_debounce_time)
  950.         {
  951.             gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
  952.             ent->pain_debounce_time = level.time + 1;
  953.         }
  954.         NoAmmoWeaponChange (ent);
  955.         return;
  956.     }
  957.  
  958.     if (is_quad)
  959.     {
  960.         damage *= 4;
  961.         kick *= 4;
  962.     }
  963.  
  964.     for (i=0 ; i<3 ; i++)
  965.     {
  966.         ent->client->kick_origin[i] = crandom() * 0.35;
  967.         ent->client->kick_angles[i] = crandom() * 0.7;
  968.     }
  969.  
  970.     for (i=0 ; i<shots ; i++)
  971.     {
  972.         // get start / end positions
  973.         AngleVectors (ent->client->v_angle, forward, right, up);
  974.         r = 7 + crandom()*4;
  975.         u = crandom()*4;
  976.         start[2] += ent->viewheight-8;
  977.         VectorSet(offset, 0, r, u + ent->viewheight-8);
  978.         P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  979.  
  980.         fire_bullet (ent, start, forward, damage, kick, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD);
  981.     }
  982.  
  983.     // send muzzle flash
  984.     gi.WriteByte (svc_muzzleflash);
  985.     gi.WriteShort (ent-g_edicts);
  986.     gi.WriteByte ((MZ_CHAINGUN1 + shots - 1) | is_silenced);
  987.     gi.multicast (ent->s.origin, MULTICAST_PVS);
  988.  
  989.     PlayerNoise(ent, start, PNOISE_WEAPON);
  990.  
  991.     ent->client->pers.inventory[ent->client->ammo_index] -= shots;
  992. }
  993.  
  994.  
  995. void Weapon_Chaingun (edict_t *ent)
  996. {
  997.     static int    pause_frames[]    = {38, 43, 51, 61, 0};
  998.     static int    fire_frames[]    = {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 0};
  999.  
  1000.     Weapon_Generic (ent, 4, 31, 61, 64, pause_frames, fire_frames, Chaingun_Fire);
  1001. }
  1002.  
  1003.  
  1004. /*
  1005. ======================================================================
  1006.  
  1007. SHOTGUN / SUPERSHOTGUN
  1008.  
  1009. ======================================================================
  1010. */
  1011.  
  1012. void weapon_shotgun_fire (edict_t *ent)
  1013. {
  1014.     vec3_t        start;
  1015.     vec3_t        forward, right;
  1016.     vec3_t        offset;
  1017.     int            damage = 4;
  1018.     int            kick = 8;
  1019.  
  1020.     if (ent->client->ps.gunframe == 9)
  1021.     {
  1022.         ent->client->ps.gunframe++;
  1023.         return;
  1024.     }
  1025.  
  1026.     AngleVectors (ent->client->v_angle, forward, right, NULL);
  1027.  
  1028.     VectorScale (forward, -2, ent->client->kick_origin);
  1029.     ent->client->kick_angles[0] = -2;
  1030.  
  1031.     VectorSet(offset, 0, 8,  ent->viewheight-8);
  1032.     P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  1033.  
  1034.     if (is_quad)
  1035.     {
  1036.         damage *= 4;
  1037.         kick *= 4;
  1038.     }
  1039.  
  1040.     if (deathmatch->value)
  1041.         fire_shotgun (ent, start, forward, damage, kick, 500, 500, DEFAULT_DEATHMATCH_SHOTGUN_COUNT);
  1042.     else
  1043.         fire_shotgun (ent, start, forward, damage, kick, 500, 500, DEFAULT_SHOTGUN_COUNT);
  1044.  
  1045.     // send muzzle flash
  1046.     gi.WriteByte (svc_muzzleflash);
  1047.     gi.WriteShort (ent-g_edicts);
  1048.     gi.WriteByte (MZ_SHOTGUN | is_silenced);
  1049.     gi.multicast (ent->s.origin, MULTICAST_PVS);
  1050.  
  1051.     ent->client->ps.gunframe++;
  1052.     PlayerNoise(ent, start, PNOISE_WEAPON);
  1053.  
  1054.     ent->client->pers.inventory[ent->client->ammo_index] -= ent->client->pers.weapon->quantity;
  1055. }
  1056.  
  1057. void Weapon_Shotgun (edict_t *ent)
  1058. {
  1059.     static int    pause_frames[]    = {22, 28, 34, 0};
  1060.     static int    fire_frames[]    = {8, 9, 0};
  1061.  
  1062.     Weapon_Generic (ent, 7, 18, 36, 39, pause_frames, fire_frames, weapon_shotgun_fire);
  1063. }
  1064.  
  1065.  
  1066. void weapon_supershotgun_fire (edict_t *ent)
  1067. {
  1068.     vec3_t        start;
  1069.     vec3_t        forward, right;
  1070.     vec3_t        offset;
  1071.     vec3_t        v;
  1072.     int            damage = 6;
  1073.     int            kick = 12;
  1074.  
  1075.     AngleVectors (ent->client->v_angle, forward, right, NULL);
  1076.  
  1077.     VectorScale (forward, -2, ent->client->kick_origin);
  1078.     ent->client->kick_angles[0] = -2;
  1079.  
  1080.     VectorSet(offset, 0, 8,  ent->viewheight-8);
  1081.     P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  1082.  
  1083.     if (is_quad)
  1084.     {
  1085.         damage *= 4;
  1086.         kick *= 4;
  1087.     }
  1088.  
  1089.     v[PITCH] = ent->client->v_angle[PITCH];
  1090.     v[YAW]   = ent->client->v_angle[YAW] - 5;
  1091.     v[ROLL]  = ent->client->v_angle[ROLL];
  1092.     AngleVectors (v, forward, NULL, NULL);
  1093.     fire_shotgun (ent, start, forward, damage, kick, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SSHOTGUN_COUNT/2);
  1094.     v[YAW]   = ent->client->v_angle[YAW] + 5;
  1095.     AngleVectors (v, forward, NULL, NULL);
  1096.     fire_shotgun (ent, start, forward, damage, kick, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SSHOTGUN_COUNT/2);
  1097.  
  1098.     // send muzzle flash
  1099.     gi.WriteByte (svc_muzzleflash);
  1100.     gi.WriteShort (ent-g_edicts);
  1101.     gi.WriteByte (MZ_SSHOTGUN | is_silenced);
  1102.     gi.multicast (ent->s.origin, MULTICAST_PVS);
  1103.  
  1104.     ent->client->ps.gunframe++;
  1105.     PlayerNoise(ent, start, PNOISE_WEAPON);
  1106.  
  1107.     ent->client->pers.inventory[ent->client->ammo_index] -= ent->client->pers.weapon->quantity;
  1108. }
  1109.  
  1110. void Weapon_SuperShotgun (edict_t *ent)
  1111. {
  1112.     static int    pause_frames[]    = {29, 42, 57, 0};
  1113.     static int    fire_frames[]    = {7, 0};
  1114.  
  1115.     Weapon_Generic (ent, 6, 17, 57, 61, pause_frames, fire_frames, weapon_supershotgun_fire);
  1116. }
  1117.  
  1118.  
  1119.  
  1120. /*
  1121. ======================================================================
  1122.  
  1123. RAILGUN
  1124.  
  1125. ======================================================================
  1126. */
  1127.  
  1128. void weapon_railgun_fire (edict_t *ent)
  1129. {
  1130.     vec3_t        start;
  1131.     vec3_t        forward, right;
  1132.     vec3_t        offset;
  1133.     int            damage;
  1134.     int            kick;
  1135.  
  1136.     if (deathmatch->value)
  1137.     {    // normal damage is too extreme in dm
  1138.         damage = 100;
  1139.         kick = 200;
  1140.     }
  1141.     else
  1142.     {
  1143.         damage = 150;
  1144.         kick = 250;
  1145.     }
  1146.  
  1147.     if (is_quad)
  1148.     {
  1149.         damage *= 4;
  1150.         kick *= 4;
  1151.     }
  1152.  
  1153.     AngleVectors (ent->client->v_angle, forward, right, NULL);
  1154.  
  1155.     VectorScale (forward, -3, ent->client->kick_origin);
  1156.     ent->client->kick_angles[0] = -3;
  1157.  
  1158.     VectorSet(offset, 0, 7,  ent->viewheight-8);
  1159.     P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  1160.     fire_rail (ent, start, forward, damage, kick);
  1161.  
  1162.     // send muzzle flash
  1163.     gi.WriteByte (svc_muzzleflash);
  1164.     gi.WriteShort (ent-g_edicts);
  1165.     gi.WriteByte (MZ_RAILGUN | is_silenced);
  1166.     gi.multicast (ent->s.origin, MULTICAST_PVS);
  1167.  
  1168.     ent->client->ps.gunframe++;
  1169.     PlayerNoise(ent, start, PNOISE_WEAPON);
  1170.  
  1171.     ent->client->pers.inventory[ent->client->ammo_index] -= ent->client->pers.weapon->quantity;
  1172. }
  1173.  
  1174.  
  1175. void Weapon_Railgun (edict_t *ent)
  1176. {
  1177.     static int    pause_frames[]    = {56, 0};
  1178.     static int    fire_frames[]    = {4, 0};
  1179.  
  1180.     Weapon_Generic (ent, 3, 18, 56, 61, pause_frames, fire_frames, weapon_railgun_fire);
  1181. }
  1182.  
  1183.  
  1184. /*
  1185. ======================================================================
  1186.  
  1187. BFG10K
  1188.  
  1189. ======================================================================
  1190. */
  1191.  
  1192. void weapon_bfg_fire (edict_t *ent)
  1193. {
  1194.     vec3_t    offset, start;
  1195.     vec3_t    forward, right;
  1196.     int        damage = 500;
  1197.     float    damage_radius = 1000;
  1198.  
  1199.     if (ent->client->ps.gunframe == 9)
  1200.     {
  1201.         // send muzzle flash
  1202.         gi.WriteByte (svc_muzzleflash);
  1203.         gi.WriteShort (ent-g_edicts);
  1204.         gi.WriteByte (MZ_BFG | is_silenced);
  1205.         gi.multicast (ent->s.origin, MULTICAST_PVS);
  1206.  
  1207.         ent->client->ps.gunframe++;
  1208.  
  1209.         PlayerNoise(ent, start, PNOISE_WEAPON);
  1210.         return;
  1211.     }
  1212.  
  1213.     if (is_quad)
  1214.         damage *= 4;
  1215.  
  1216.     AngleVectors (ent->client->v_angle, forward, right, NULL);
  1217.  
  1218.     VectorScale (forward, -2, ent->client->kick_origin);
  1219.  
  1220.     // make a big pitch kick with an inverse fall
  1221.     ent->client->v_dmg_pitch = -40;
  1222.     ent->client->v_dmg_roll = crandom()*8;
  1223.     ent->client->v_dmg_time = level.time + DAMAGE_TIME;
  1224.  
  1225.     VectorSet(offset, 8, 8, ent->viewheight-8);
  1226.     P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  1227.     fire_bfg (ent, start, forward, damage, 400, damage_radius);
  1228.  
  1229.     ent->client->ps.gunframe++;
  1230.  
  1231.     PlayerNoise(ent, start, PNOISE_WEAPON);
  1232.  
  1233.     ent->client->pers.inventory[ent->client->ammo_index] -= ent->client->pers.weapon->quantity;
  1234. }
  1235.  
  1236. void Weapon_BFG (edict_t *ent)
  1237. {
  1238.     static int    pause_frames[]    = {39, 45, 50, 55, 0};
  1239.     static int    fire_frames[]    = {9, 17, 0};
  1240.  
  1241.     Weapon_Generic (ent, 8, 32, 55, 58, pause_frames, fire_frames, weapon_bfg_fire);
  1242. }
  1243.  
  1244.  
  1245. //======================================================================
  1246.